#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
#include "vector_binario.h"
#include "vector_dinamico.h"

/* ******************************************************************
 *                DEFINICION DE LOS TIPOS DE DATOS					*
 * *****************************************************************/

/* IMPORTANTE: La inclusión del término "vector" dentro de su nombre
 * es un abuso del lenguaje ya que esta estructura no vendría a representar
 * más que un número binario al cual sólo se le puede agregar un bit
 * al final por operación y no se puede borrar ninguno ya escrito. */
struct _vector_bin {
	vector_dinamico_t* buffer;
};

/* ******************************************************************
 *                IMPLEMENTACION DE PRIMITIVAS						*
 * *****************************************************************/

/* Crea y devuelve un vector binario vacío de tamaño largo2. */
vector_binario_t* v_binario_crear (int largo2) {
	vector_binario_t* vec = malloc ( sizeof (vector_binario_t) );
	if (!vec) return NULL;
	
	vec->buffer = vector_crear (largo2, free);
	if (! (vec->buffer) ) {
		free (vec);
		return NULL;
	}
	return vec;
}

/* Almacena el bit al final del vector.
 * Pre: el vector fue creado.
 * Devuelve false en caso de error y true si el bit fue guardado con éxito. */
bool v_binario_agregar (vector_binario_t* vec, bool bit) {
	if (!vec) return false;
	
	int tam = vector_tamanio (vec->buffer);
	int cant = vector_cantidad (vec->buffer);
	if (cant == tam) {
		bool resultado = vector_redimensionar ( vec->buffer, tam * 2);
		if (!resultado) return false;
	}
	
	int* num_ptr = malloc (sizeof(int));
	if (!num_ptr) return false;
	
	if (bit) (*num_ptr) = 1;
		else (*num_ptr) = 0;
	
	return ( vector_guardar (vec->buffer, cant, num_ptr) );
}

/* Devuelve el bit guardado en la posición 'pos' del vector.
 * Devuelve -1 si la posición es inválida.
 * Pre: el vector fue creado.
 * Post: el bit fue devuelto. */
int v_binario_obtener (vector_binario_t* vec, size_t pos) {
	if (!vec) return -1;
	void* ptr = vector_obtener (vec->buffer, pos);
	if (!ptr) return -1;
	int* num = (int*) ptr;
	return (*num);
}

/* Devuelve la cantidad de bits que posee el vector binario.
 * Pre: el vector fue creado. */
int v_binario_largo (vector_binario_t* vec) {
	if (!vec) return 0;
	return ( vector_cantidad (vec->buffer) );
}

/* Invierte el orden de los bits almacenados.
 * Pre: el vector fue creado.
 * Post: el orden de los bits fue invertido. */
void v_binario_invertir (vector_binario_t* vec) {
	if (!vec) return;
	
	int cant = vector_cantidad (vec->buffer);
	int pos_inf = 0;
	int pos_sup = cant - 1;
	while ( pos_inf < pos_sup ) {
		void* valor_inf = vector_borrar (vec->buffer, pos_inf);
		void* valor_sup = vector_borrar (vec->buffer, pos_sup);
		vector_guardar (vec->buffer, pos_inf, valor_sup);
		vector_guardar (vec->buffer, pos_sup, valor_inf);
		pos_inf++;
		pos_sup--;
	}
}

/* Imprime al vector binario por pantalla.
 * Nota: Puede servir para pruebas MUY caseras. Lo ideal sería ir
 * obteniendo cada bit posición a posición, comparando cada uno de ellos
 * con los datos de prueba y emitir un booleano como resultado */
void v_binario_imprimir (vector_binario_t* vec) {
	if (!vec) return;
	int cant = vector_cantidad (vec->buffer);
	for ( int i = 0 ; i < cant ; i++ ) {
		int* num = vector_obtener (vec->buffer, i);
		printf ("%d", *num);
	}
}

/* Primitiva en desuso por el momento */
void v_binario_escribir (vector_binario_t* vec, FILE* archivo) {
	/*
	for ( int i = 0 ; i < (vec->ocupados) ; i++ ) {
		fprintf (archivo, "%d", vec->datos[i]);
	}
	*/
}

/* Destruye el vector binario.
 * Pre: el vector binario es válido.
 * Post: se eliminó al vector binario y todos sus elementos. */
void v_binario_destruir (vector_binario_t* vec) {
	if (!vec) return;
	vector_destruir (vec->buffer);
	free (vec);
}
